package ai;

import java.util.Random;


import com.jme.math.FastMath;

import logic.DelayedTPController;
import logic.common.game.GameMode;
import logic.common.player.Player;
import logic.common.team.Team;
import logic.nodes.TeamNode;
import logic.ships.hunter.Hunter;
import logic.ships.mothership.MotherShip;
import map.spawnStation.SpawnStation;

public class TeamAIController extends DelayedTPController {
	
	private static final long serialVersionUID = 1L;
	
	private static final float CAPTURE_PROP = FastMath.ONE_THIRD;
	private static final float MIN_SHIELDS_RATIO = 0.5f;
		
	private Team team;
	private int conqueringBots, motherShipBots, currentBotIndex;
	private Player bot;
	private Random r;
	
	public TeamAIController(Team team) {
		super(0.2f);
		this.team = team;
		
		r = new Random();
	}
	
	public void initControllers() {
		motherShipBots = team.getBots().size();
	}
	
	@Override
	protected void delayedUpdate(float time) {
		bot = team.getBots().get(currentBotIndex);
		handleBot();
		
		currentBotIndex++;
		if(currentBotIndex >= team.getBots().size()) currentBotIndex = 0;
	}
	
	protected void handleBot() {
		TeamNode target = bot.getBotTarget();
				
		if(target == null) findNewTarget();
		else if(target instanceof MotherShip) {
			boolean isNearMS = isNearMotherShip();
						
			if(!isNearMS && motherShipBots > 1) findNewTarget();
			else if(isNearMS) checkHunterTarget(300f);
		} else if(target instanceof SpawnStation) {
			if(checkHunterTarget(150f)) return;
			
			SpawnStation station = (SpawnStation)target;
			if(station.getTeam() == team) findNewTarget();
		} else if(target instanceof Hunter) {
			Hunter hunter = (Hunter)target;
			if(hunter.isDestroyed() || noShieldsLoss(hunter)) findNewTarget();
		}
	}
	
	protected boolean checkHunterTarget(float maxDist) {
		Hunter nearHunter = getNearestHunter();
		if(nearHunter == null) return false;
		
		float dist = nearHunter.getLocalTranslation().distance(bot.getHunter().getLocalTranslation());
		if(dist <= maxDist) {
			setNewTarget(nearHunter);
			return true;
		}
		return false;
	}
	
	protected boolean noShieldsLoss(Hunter hunter) {
		PilotController c = bot.getPilotController();
		return c.isAttacking() && c.getChaseTime() >= 10f &&
				hunter.getCurrentShield() / hunter.getMaxShield() > MIN_SHIELDS_RATIO;
	}
	
	protected void findNewTarget() {
		if(isNearMotherShip()) setNewTarget(bot.getEnemyTeam().getMotherShip());
		else {
			float next = r.nextFloat();
			
			int teamStations = team.getSpawnStations().size();
			int gameStations = team.getGame().getMap().getSpawnStations().size();
			
			if(next <= CAPTURE_PROP && teamStations < gameStations 
			&& conqueringBots < team.getBots().size() / 3) setNewTarget(getNearestSpawnStation());
			else setHunterTarget();	
		}
	}
	
	protected boolean isNearMotherShip() {
		GameMode mode = team.getGame().getGameCycle().getGameMode();
		if(mode != GameMode.Destruction) return false;
		
		float dist = bot.getEnemyTeam().getMotherShipSpawn().distance(bot.getHunter().getLocalTranslation());
		return dist <= 300f;
	}
	
	protected void setHunterTarget() {
		setNewTarget(getNearestHunter());
	}
	
	protected Hunter getNearestHunter() {
		return bot.getEnemyTeam().getNearestHunter(bot.getHunter().getLocalTranslation());
	}
	
	protected SpawnStation getNearestSpawnStation() {
		SpawnStation nearestStation = null;
		float minDist = Float.POSITIVE_INFINITY;
		
		for(SpawnStation station : team.getGame().getMap().getSpawnStations()) {				
			if(station.getTeam() != team) {
				float dist = station.getLocalTranslation().distance(bot.getHunter().getLocalTranslation());
				if(dist < minDist) {
					minDist = dist;
					nearestStation = station;
				}
			}
		}
		
		return nearestStation;
	}
	
	protected void setNewTarget(final TeamNode target) {
		TeamNode oldTarget = bot.getBotTarget();
		if(oldTarget == target || target == null) return;
		
		if(oldTarget != null) {
			if(oldTarget instanceof SpawnStation && !(target instanceof SpawnStation)) 
				conqueringBots--;
			else if(oldTarget instanceof MotherShip) motherShipBots--;
		}
		
		if(target instanceof SpawnStation) conqueringBots++;
		else if(target instanceof MotherShip) motherShipBots++;
		
		team.getIngameState().getThreadPool().addPostRunnable(new Runnable() {
			@Override
			public void run() {
				bot.changeBotTarget(target);
			}
		});
	}
}